/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class X2DBuffer {
    static ARRAY_SIZE = 1024 * 1024 * 4 * 2;
    static TRIANGLE_MAX = parseInt(X2DBuffer.ARRAY_SIZE / 4 / 13 / 3);
    static ELEMENT_SIZE = 1024 * 64;
    static Init() {
        X2DBuffer.ARRAY = new ArrayBuffer(X2DBuffer.ARRAY_SIZE);//8m 字节
        X2DBuffer.FLOAT32 = new Float32Array(X2DBuffer.ARRAY);//2m float

        X2DBuffer.ELEMENT = new ArrayBuffer(X2DBuffer.ELEMENT_SIZE);//65536
        X2DBuffer.UINT16 = new Uint16Array(X2DBuffer.ELEMENT);

        X2DBuffer.TMP_MAT = new XMat4();
    }
    static TMP_MAT = null;
    static Transform(x, y, sw, sh, ra, ox, oy, realw, realh) {
        X2DBuffer.TMP_MAT.Unit()
        if (ox == -1) ox = 0
        if (ox == -2) ox = Math.floor(realw / 2)
        if (ox == -3) ox = realw
        if (oy == -1) oy = 0
        if (oy == -2) oy = Math.floor(realh / 2)
        if (oy == -3) oy = realh
        if (ox != 0 || oy != 0) X2DBuffer.TMP_MAT.Move(-ox, -oy, 0)
        if (sw != 1 || sh != 1) X2DBuffer.TMP_MAT.Scale(sw, sh, 1)
        if (ra != 0) X2DBuffer.TMP_MAT.Rotate(0, 0, -ra)
        if (x != 0 || y != 0) X2DBuffer.TMP_MAT.Move(x, y, 0)
    }
    static ARRAY_POINT = 0;
    static ELEMENT_POINT = 0;
    static PutCutEx(pcut, m00, m01, m10, m11, m22, m30, m31, c = 0xffffffff) {
        if (c == -1) c = 0xffffffff;
        c = X2DBuffer.SwapC(c);
        X2DBuffer.FLOAT32.set([0.0, 0.0, c, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[pcut.rid],
            pcut.w, 0.0, c, pcut.u1, pcut.v1, m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[pcut.rid],
            pcut.w, pcut.h, c, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[pcut.rid],
            0.0, pcut.h, c, pcut.u3, pcut.v3, m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[pcut.rid]],
            X2DBuffer.ARRAY_POINT);
        let p = X2DBuffer.ARRAY_POINT / 13;
        X2DBuffer.UINT16.set([p, p + 1, p + 2, p + 2, p + 3, p], X2DBuffer.ELEMENT_POINT);
        X2DBuffer.ARRAY_POINT += 13 * 4;
        X2DBuffer.ELEMENT_POINT += 6;
    }
    static PutCut(pcut, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
        // X2DBuffer.Transform(parseInt(x), parseInt(y), sw, sh, ra, ox, oy, pcut.w, pcut.h);
        X2DBuffer.Transform(x, y, sw, sh, ra, ox, oy, pcut.w, pcut.h);
        let tmat = X2DBuffer.TMP_MAT.mat;
        X2DBuffer.PutCutEx(pcut, tmat[0][0], tmat[0][1], tmat[1][0], tmat[1][1], tmat[2][2], tmat[3][0], tmat[3][1], c);
    }
    static PutRawEx(rid, vs, is, m00, m01, m10, m11, m22, m30, m31, c = 0xffffffff) {
        c = X2DBuffer.SwapC(c);
        for (let i = 0; i < vs.length / 4; i++) {
            X2DBuffer.FLOAT32.set([vs[i * 4], vs[i * 4 + 1], c, vs[i * 4 + 2], vs[i * 4 + 3], m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[rid]],
                X2DBuffer.ARRAY_POINT + i * 13);
        }
        let p = X2DBuffer.ARRAY_POINT / 13;
        X2DBuffer.UINT16.set(is, X2DBuffer.ELEMENT_POINT);
        for (let i = 0; i < is.length; i++) {
            X2DBuffer.UINT16[X2DBuffer.ELEMENT_POINT++] += p;
        }
        X2DBuffer.ARRAY_POINT += 13 * vs.length / 4;
    }
    static PutRaw(rid, vs, is, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
        X2DBuffer.Transform(parseInt(x), parseInt(y), sw, sh, ra, ox, oy, XTexture.ximages[rid].w, XTexture.ximages[rid].h);
        let tmat = X2DBuffer.TMP_MAT.mat;
        X2DBuffer.PutRawEx(rid, vs, is, tmat[0][0], tmat[0][1], tmat[1][0], tmat[1][1], tmat[2][2], tmat[3][0], tmat[3][1], c);
    }
    // static PutTriangleEx(pcut, m00, m01, m10, m11, m22, m30, m31, c = 0xffffffff) {
    //     if (c == -1) c = 0xffffffff;
    //     c = X2DBuffer.SwapC(c)
    //     let p = X2DBuffer.ARRAY_POINT * 13 * 3;
    //     X2DBuffer.FLOAT32.set([0.0, 0.0, c, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[pcut.rid],
    //         pcut.w, 0.0, c, pcut.u1, pcut.v1, m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[pcut.rid],
    //         pcut.w, pcut.h, c, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, X2DBuffer.RID_DICT[pcut.rid]],
    //         p);
    //     X2DBuffer.ARRAY_POINT += 1;
    // }
    static SwapC(c) {
        let r = Math.floor(((c >> 16) & 0xff) * 63 / 255)
        let g = Math.floor(((c >> 8) & 0xff) * 63 / 255)
        let b = Math.floor((c & 0xff) * 63 / 255)
        let a = Math.floor(((c >> 24) & 0xff) * 63 / 255)
        return ((a * 64 + r) * 64 + g) * 64 + b
    }
    static RID_DICT = {};
    static RID_POINT = 0;
    static PutRid(rid) {
        if (rid in X2DBuffer.RID_DICT) {
            return true;
        }
        if (X2DBuffer.RID_POINT >= 16) {
            return false;
        }
        X2DBuffer.RID_DICT[rid] = X2DBuffer.RID_POINT++;
        return true;
    }
    static ClearBuffer() {
        X2DBuffer.RID_DICT = {};
        X2DBuffer.RID_POINT = 0;
        X2DBuffer.ARRAY_POINT = 0;
        X2DBuffer.ELEMENT_POINT = 0;
        // this.drawCount = 0
    }
}

class X2DBeta {
    constructor() {
    }
    static COUNT_FLUSH = 0;

    static Init() {
        X2DBuffer.Init();

        X2DBeta.WHITE_IMG_1X1 = XTexture.LoadTextureFromImage("CUSTOM_TEXTURE_1");
        X2DBeta.WHITE_CUT_1X1 = XTexture.MakeCut(X2DBeta.WHITE_IMG_1X1, 0, 0, 1, 1);

        X2DBeta.Clear();

        X2DBeta.ARRAY_BUFFER = window.gl.createBuffer();
        X2DBeta.ELEMENT_BUFFER = window.gl.createBuffer();

        X2DBeta.WORLD_MAT = new XMat4();
        X2DBeta.WORLD_MAT.Unit()
        X2DBeta.WORLD_MAT.X2DMat(0, 0, Scr.logicw, Scr.logich);
        X2DBeta.TEXT_MAT = new XMat4();
        X2DBeta.TEXT_MAT.Unit()
        X2DBeta.TEXT_MAT.X2DMat(0, 0, Scr.realw, Scr.realh);
    }
    static Clear() {
        X2DBuffer.ClearBuffer();
    }
    static drawLine(x1, y1, x2, y2, c = 0xffffffff, linewidth = 1) {
        if (x1 < 0 && x2 < 0)
            return;
        if (y1 < 0 && y2 < 0)
            return;
        if (x1 > Scr.logicw && x2 > Scr.logicw)
            return;
        if (y1 > Scr.logich && y2 > Scr.logich)
            return;
        // let a = XTools.fAngle(x2 - x1, y2 - y1);
        // let w = XTools.iDistance(x1 - x2, y1 - y2);
        // let dx = Math.cos(-a * Math.PI / 180) * w / 2;
        // let dy = Math.sin(-a * Math.PI / 180) * w / 2;
        // // X2DBeta.drawCut(X2DBeta.WHITE_CUT_1X1, x1  , y1  ,
        // //     XTools.iDistance(x1 - x2, y1 - y2) + linewidth, linewidth, a, 0, 0, c);
        // // w = parseInt(w + linewidth);
        // // if (w % 2 != 0) w -= 1;
        // X2DBeta.drawCut(X2DBeta.WHITE_CUT_1X1, x1 + dx, y1 + dy,
        //     w + linewidth, linewidth, a, 0.5, 0.5, c);
        let a = XTools.fAngle(x2 - x1, y2 - y1);
        let w = XTools.iDistance(x1 - x2, y1 - y2);
        let dx = Math.cos((-a - 45 - 90) * Math.PI / 180) * 1.4142135623730951 * linewidth / 2;
        let dy = Math.sin((-a - 45 - 90) * Math.PI / 180) * 1.4142135623730951 * linewidth / 2;
        X2DBeta.drawCut(X2DBeta.WHITE_CUT_1X1, x1 + dx + 0.5, y1 + dy + 0.5, w + linewidth, linewidth, a, 0, 0, c)
    }
    static Flush() {
        if (X2DBuffer.RID_POINT <= 0 || X2DBuffer.ARRAY_POINT == 0) {
            return;
        }
        let ps = XShader.gi().use(XShader.ID_SHADER_FAST)
        for (let rid in X2DBuffer.RID_DICT) {
            let tnum = X2DBuffer.RID_DICT[rid];
            window.gl.activeTexture(window.gl.TEXTURE0 + tnum)
            window.gl.bindTexture(window.gl.TEXTURE_2D, XTexture.ximages[rid].tex);
            window.gl.uniform1i(ps.tex[tnum], tnum);
        }

        window.gl.uniformMatrix4fv(ps.uMat, false, X2DBeta.WORLD_MAT.ForShader())

        window.gl.bindBuffer(window.gl.ARRAY_BUFFER, X2DBeta.ARRAY_BUFFER);
        window.gl.bufferData(window.gl.ARRAY_BUFFER, X2DBuffer.ARRAY, window.gl.STATIC_DRAW)
        window.gl.vertexAttribPointer(ps.position, 3, window.gl.FLOAT, false, 4 * 13, 0)
        window.gl.enableVertexAttribArray(ps.position)
        window.gl.vertexAttribPointer(ps.aTexCoord, 2, window.gl.FLOAT, false, 4 * 13, 4 * 3)
        window.gl.enableVertexAttribArray(ps.aTexCoord)
        window.gl.vertexAttribPointer(ps.ext1, 4, window.gl.FLOAT, false, 4 * 13, 4 * 5)
        window.gl.enableVertexAttribArray(ps.ext1)
        window.gl.vertexAttribPointer(ps.ext2, 4, window.gl.FLOAT, false, 4 * 13, 4 * 9)
        window.gl.enableVertexAttribArray(ps.ext2)

        // window.gl.drawArrays(gl.TRIANGLES, 0, 3 * X2DBuffer.ARRAY_POINT);

        window.gl.bindBuffer(window.gl.ELEMENT_ARRAY_BUFFER, X2DBeta.ELEMENT_BUFFER);
        window.gl.bufferData(window.gl.ELEMENT_ARRAY_BUFFER, X2DBuffer.ELEMENT, window.gl.STATIC_DRAW);
        window.gl.drawElements(window.gl.TRIANGLES, X2DBuffer.ELEMENT_POINT, window.gl.UNSIGNED_SHORT, 0);

        X2DBeta.Clear();
        X2DBeta.COUNT_FLUSH++;
    }
    static _AddRid(rid) {
        if (X2DBuffer.PutRid(rid)) {
            return true;
        }
        X2DBeta.Flush();
        return -1;
    }
    // static AddAnimaRes(nid_rid) {
    //     for (let nid in nid_rid) {
    //         let rid = nid_rid[nid];
    //         if (X2DBeta._AddRid(rid, nid) == -1) {
    //             X2DBeta.AddAnimaRes(nid_rid);
    //             return;
    //         }
    //     }
    // }
    static MATRIX_STACK = [];
    static PushMatrix() {
        X2DBeta.MATRIX_STACK.push([(new XMat4()).Copy(X2DBeta.WORLD_MAT), (new XMat4()).Copy(X2DBeta.TEXT_MAT)]);
    }
    static PopMatrix() {
        if (X2DBeta.MATRIX_STACK.length > 0) {
            let t = X2DBeta.MATRIX_STACK.pop();
            X2DBeta.WORLD_MAT.Copy(t[0]);
            X2DBeta.TEXT_MAT.Copy(t[1]);
        }
    }
    static BLENDER_MODE = -1;
    static BlenderMode(mode) {
        if (X2DBeta.BLENDER_MODE == mode) {
            return;
        }
        X2DBeta.Flush();
        X2DBeta.BLENDER_MODE = mode;
        switch (mode) {
            case 0:
                window.gl.blendFunc(window.gl.SRC_ALPHA, window.gl.ONE_MINUS_SRC_ALPHA);
                break;
            case 1:
                window.gl.blendFunc(window.gl.SRC_ALPHA, window.gl.ONE);
                break;
        }
    }
    static CLIP_STACK = [];
    static PushClip(x, y, w, h) {
        X2DBeta.Flush();
        y = Scr.logich - y - h;
        X2DBeta.CLIP_STACK.push([x, y, w, h]);

        if (w > 0 && h > 0) {
            window.gl.enable(window.gl.SCISSOR_TEST);
            window.gl.scissor(x, y, w, h);
        }
    }
    static PopClip() {
        X2DBeta.Flush();
        X2DBeta.CLIP_STACK.pop();
        if (X2DBeta.CLIP_STACK.length == 0) {
            window.gl.disable(window.gl.SCISSOR_TEST);
        }
        else {
            window.gl.scissor(...X2DBeta.CLIP_STACK[X2DBeta.CLIP_STACK.length - 1]);
        }
    }
    static CheckTransformDataOverride(needSize = 20) {
        if (X2DBuffer.ARRAY_POINT + needSize > X2DBuffer.TRIANGLE_MAX) {
            X2DBeta.Flush();
            return true;
        }
        return false;
    }
    // static DrawAnimaEle(ani_p, ep, frame, x, y, sw, sh, ra, c) {
    //     X2DBeta.AddIndex();

    //     X2DBeta.TRANSFORM_DATA_F32.set([
    //         1, ani_p, frame, ep, //type,ani_p,frame,ele_offset
    //         x, y, sw, sh, //x,y,sw,sh,
    //         ra, 0, c >>> 16, c & 0xffff],//ra,0,c high,c low
    //         X2DBeta.TRANSFORM_POINT);
    //     X2DBeta.TRANSFORM_POINT += 12;
    // }
    // static FillTriangleEx(x1, y1, c1, x2, y2, c2, x3, y3, c3) {
    //     X2DBeta.CheckTransformDataOverride();

    //     X2DBeta.AddIndex(3);

    //     X2DBeta.TRANSFORM_DATA_F32.set([
    //         2, 0, 0, 0, //type,0,0,0
    //         x1, y1, c1 >>> 16, c1 & 0xffff,
    //         x2, y2, c2 >>> 16, c2 & 0xffff,
    //         x3, y3, c3 >>> 16, c3 & 0xffff],
    //         X2DBeta.TRANSFORM_POINT);
    //     X2DBeta.TRANSFORM_POINT += 16;
    // }
    static fillRect(x, y, w, h, c = 0xffffffff) {
        X2DBeta.drawCut(X2DBeta.WHITE_CUT_1X1, x, y, w, h, 0, 0, 0, c);
    }
    // static fillRectEx(x1, y1, c1, x2, y2, c2, x3, y3, c3, x4, y4, c4) {
    //     X2DBeta.CheckTransformDataOverride();

    //     X2DBeta.AddIndex();

    //     X2DBeta.TRANSFORM_DATA_F32.set([
    //         2, 0, 0, 0, //type,0,0,0
    //         x1, y1, c1 >>> 16, c1 & 0xffff,
    //         x2, y2, c2 >>> 16, c2 & 0xffff,
    //         x3, y3, c3 >>> 16, c3 & 0xffff,
    //         x4, y4, c4 >>> 16, c4 & 0xffff],
    //         X2DBeta.TRANSFORM_POINT);
    //     X2DBeta.TRANSFORM_POINT += 20;
    // }
    static drawText(s, size = 24, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
        if (s.length <= 0) return 0;
        size = parseInt(size * XTools.SCALE_TEXT + 0.999);
        if (y < -size) return 0;
        if (y > Scr.logich + size) return 0;
        sw /= XTools.SCALE_TEXT * XTools.GLOBAL_DPR;
        sh /= XTools.SCALE_TEXT * XTools.GLOBAL_DPR;
        // if (y < -size)
        //     return;
        // if (y > Scr.logich + size)
        //     return;
        // x = x * Scr.rate;
        // y = y * Scr.rate;
        // size = parseInt(size * Scr.rate + 0.5);
        // // ox=ox*Scr.rate;
        // // oy=oy*Scr.rate;
        let cid = XTexture.GetText(s, size);
        X2DBeta.drawCut(cid, x, y, sw, sh, ra, ox, oy, c);
        return parseInt(XTexture.all_cuts[cid].w * sw);
    }
    static drawCut(cid, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
        if (cid == -1) {
            return;
        }
        let pcut = XTexture.all_cuts[cid];
        if (pcut == null) {
            return true;
        }
        X2DBeta.CheckTransformDataOverride();//step 1 超过上限先渲染
        if (X2DBeta._AddRid(pcut.rid) == -1) {// step 2 超过上限先渲染
            X2DBeta._AddRid(pcut.rid);//再次填充
        }
        X2DBuffer.PutCut(pcut, x, y, pcut.sw * sw, pcut.sh * sh, ra, ox, oy, c);
    }
    static drawCutEx(cid, tmat, c = 0xffffffff) {
        if (cid == -1) {
            return;
        }
        let pcut = XTexture.all_cuts[cid];
        if (pcut == null) {
            return true;
        }
        X2DBeta.CheckTransformDataOverride();//step 1 超过上限先渲染
        if (X2DBeta._AddRid(pcut.rid) == -1) {// step 2 超过上限先渲染
            X2DBeta._AddRid(pcut.rid);//再次填充
        }
        X2DBuffer.PutCutEx(pcut, tmat[0][0], tmat[0][1], tmat[1][0], tmat[1][1], tmat[2][2], tmat[3][0], tmat[3][1], c);
    }
    static DrawRawCut(rid, xyuv, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
        X2DBeta.CheckTransformDataOverride();//step 1 超过上限先渲染
        if (X2DBeta._AddRid(rid) == -1) {// step 2 超过上限先渲染
            X2DBeta._AddRid(rid);//再次填充
        }
        X2DBuffer.PutRaw(rid, xyuv, [0, 1, 2, 2, 3, 0], x, y, sw, sh, ra, ox, oy, c);
    }
    static DrawRawCutEx(rid, xyuv, idx, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
        X2DBeta.CheckTransformDataOverride();//step 1 超过上限先渲染
        if (X2DBeta._AddRid(rid) == -1) {// step 2 超过上限先渲染
            X2DBeta._AddRid(rid);//再次填充
        }
        X2DBuffer.PutRaw(rid, xyuv, idx, x, y, sw, sh, ra, ox, oy, c);
    }
    static Circle(ox, oy, rw, rh, a1, a2, c = 0xffffffff) {
        X2DBeta.CheckTransformDataOverride();//step 1 超过上限先渲染
        if (X2DBeta._AddRid(X2DBeta.WHITE_IMG_1X1) == -1) {// step 2 超过上限先渲染
            X2DBeta._AddRid(X2DBeta.WHITE_IMG_1X1);//再次填充
        }
        let count = parseInt(Math.sqrt(rw * rw + rh * rh) / 2 + 1);
        if (count < 6) count = 6;
        a1 = a1 * Math.PI / 180;
        a2 = a2 * Math.PI / 180;
        let gap = (a2 - a1) / count;
        let xyuv = [0, 0, 0, 0];
        let idx = [];
        for (let i = 0; i < count + 1; i++) {
            xyuv.push(Math.cos(a1), Math.sin(a1), 1, 1);
            a1 += gap;
            if (i < count) idx.push(0, i + 1, i + 2);
        }
        this.DrawRawCutEx(X2DBeta.WHITE_IMG_1X1, xyuv, idx, ox, oy, rw, rh, 0, 0, 0, c);
    }
    static ring(ox, oy, rw, rh, a1 = 0, a2 = 360, c = 0xffffffff, lw = 1) {
        X2DBeta.CheckTransformDataOverride();//step 1 超过上限先渲染
        if (X2DBeta._AddRid(X2DBeta.WHITE_IMG_1X1) == -1) {// step 2 超过上限先渲染
            X2DBeta._AddRid(X2DBeta.WHITE_IMG_1X1);//再次填充
        }
        let count = parseInt(Math.sqrt(rw * rw + rh * rh) / 2 + 1);
        if (count < 6) count = 6;
        a1 = a1 * Math.PI / 180;
        a2 = a2 * Math.PI / 180;
        let gap = (a2 - a1) / count;
        let xyuv = [];
        let idx = [];
        for (let i = 0; i < count + 1; i++) {
            xyuv.push(Math.cos(a1) * rw, Math.sin(a1) * rh, 1, 1);
            xyuv.push(Math.cos(a1) * (rw - lw), Math.sin(a1) * (rh - lw), 1, 1);
            a1 += gap;
            if (i < count) {
                idx.push(i * 2, i * 2 + 2, i * 2 + 3);
                idx.push(i * 2, i * 2 + 3, i * 2 + 1);
            }
        }
        this.DrawRawCutEx(X2DBeta.WHITE_IMG_1X1, xyuv, idx, ox, oy, 1, 1, 0, 0, 0, c);
    }

    static drawRect(x, y, w, h, c = 0xffffffff, lw = 1) {
        X2DBeta.drawLine(x, y, x + w, y, c, lw);
        X2DBeta.drawLine(x, y + h, x + w, y + h, c, lw);

        X2DBeta.drawLine(x + w, y, x + w, y + h, c, lw);
        X2DBeta.drawLine(x, y, x, y + h, c, lw);
    }
    static drawRectByMat(x1, y1, x2, y2, mat, c) {
        let v1 = mat.Transform2DVertex(x1, y1);
        let v2 = mat.Transform2DVertex(x2, y1);
        let v3 = mat.Transform2DVertex(x2, y2);
        let v4 = mat.Transform2DVertex(x1, y2);
        X2DBeta.drawLine(v1[0], v1[1], v2[0], v2[1], c);
        X2DBeta.drawLine(v3[0], v3[1], v2[0], v2[1], c);
        X2DBeta.drawLine(v3[0], v3[1], v4[0], v4[1], c);
        X2DBeta.drawLine(v1[0], v1[1], v4[0], v4[1], c);
    }

    static getTextWidth(s, size) {
        if (s.length <= 0) return 0;
        size = parseInt(size * XTools.SCALE_TEXT + 0.999);
        let sw = 1 / (XTools.SCALE_TEXT * XTools.GLOBAL_DPR);
        let cid = XTexture.GetText(s, size);
        return parseInt(XTexture.all_cuts[cid].w * sw);
    }
    static getTextWidthEx(sss, size) {
        let ret = 0;
        for (let ss of sss) {
            for (let s of ss.split("\n")) {
                ret = Math.max(this.getTextWidth(s, size), ret);
            }
        }
        return ret;
    }
    static swapMode2D() {
        window.gl.disable(window.gl.DEPTH_TEST);

        window.gl.enable(window.gl.BLEND);
        X2DBeta.BlenderMode(0);

        //window.gl.enable(window.gl.ALPHA_TEST)
        //window.gl.alphaFunc(window.gl.GREATER, 0.01)
        // X2DBeta.PushClip(0, 0, Scr.logicw, Scr.logich);

        X2DBeta.Clear();
    }
}

module.exports = {
    X2DBeta
}

const { Scr } = require("../../XDefine");
const { XMat4 } = require("../XMat4");
const { XShader } = require("./XShader");
const { XTexture } = require("../XTexture");
const { XTools } = require("../../XTools.js");
